import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import $ from 'jquery';

import { TimeTrigger } from '../utils/timeUtils';

import Button, { BDP_BUTTON } from './index';
import A from '../A';

export const BDP_DROPDOWN = 'BDP_DROPDOWN';

class DropDown extends React.Component {
	constructor() {
		super();
		this.state = {
			open: false,
		};
		this.timeTrigger = new TimeTrigger();
		this.timeTrigger.subscribe(this.doTrigger);
	}

	componentDidMount() {
		window.addEventListener('click', this.hideDrillDown);
	}

	componentWillUnmount() {
		window.removeEventListener('click', this.hideDrillDown);
	}

	onMouseEnter = () => {
		if (this.props.hover && !this.props.disabled) {
			this.timeTrigger.next(true, 50);
		}
	};

	onMouseLeave = () => {
		if (this.props.hover) {
			this.timeTrigger.next(false, 30);
		}
	};

	onDrillDownTrigger = () => {
		this.timeTrigger.next(!this.state.open, 20);
	};

	setHolderRef = (ele) => {
		this.$holder = ele;
	};

	setListRef = (ele) => {
		this.$list = ele;
	};

	doTrigger = (open) => {
		const myOpen = open !== undefined ? open : !this.state.open;
		this.setState({ open: myOpen });

		this.lock = true;

		if (myOpen) {
			const { placement = '', isNest } = this.props;
			const right = placement.includes('right');
			const top = placement.includes('top');

			const { left: holderLeft, top: holderTop } = $(this.$holder).offset();
			const holderRect = this.$holder.getBoundingClientRect();

			Promise.resolve().then(() => {
				let offset;
				const listRect = this.$list.getBoundingClientRect();

				if (isNest) {
					offset = {
						left: right ? holderLeft - listRect.width : holderLeft + holderRect.width,
						top: holderTop - 6,
					};
				} else {
					offset = {
						left: right ? (holderLeft + holderRect.width) - listRect.width : holderLeft,
						top: top ? holderTop - listRect.height : holderTop + holderRect.height,
					};
				}

				$(this.$list).offset(offset);
			});
		}
	};

	hideDrillDown = () => {
		this.timeTrigger.next(false, 10);
	};

	render() {
		const { title, size, isNest, disabled, placement, type = 'default', children } = this.props;
		const { open } = this.state;
		const right = placement.includes('right');

		const $children = React.Children.map(children, (node) => {
			if (React.isValidElement(node)) {
				if (node.type[BDP_BUTTON] === BDP_BUTTON) {
					const { disabled: subDisabled, type: subType, ...props } = node.props;

					return (
						<li className={classNames({ disabled: subDisabled }, subType)}>
							<A role="button" {...props} />
						</li>
					);
				} else if (node.type[BDP_DROPDOWN] === BDP_DROPDOWN) {
					const { type: subType, ...props } = node.props;
					const clone = React.cloneElement(node, {
						isNest: true,
						hover: true,
						placement,
						...props,
					});

					return (
						<li className={classNames({ disabled }, subType)}>
							{clone}
						</li>
					);
				}
			}
			return node;
		});

		return (
			<div
				className={classNames('dropdown bdp-dropdown', { open, disabled })} ref={this.setHolderRef}
				onMouseEnter={this.onMouseEnter} onMouseLeave={this.onMouseLeave}
			>
				<Button
					onClick={this.onDrillDownTrigger}
					size={size} type={type}
				>
					{title}{' '}
					{isNest ?
						<span className={`fa fa-caret-${right ? 'left' : 'right'}`} /> :
						<span className="caret" /> }
				</Button>
				<ul className="dropdown-menu" ref={this.setListRef}>
					{$children}
				</ul>
			</div>
		);
	}
}

DropDown[BDP_DROPDOWN] = BDP_DROPDOWN;

DropDown.propTypes = {
	children: PropTypes.node,
	title: PropTypes.node,
	type: PropTypes.string,
	size: PropTypes.string,
	placement: PropTypes.string,
	hover: PropTypes.bool,
	disabled: PropTypes.bool,
	isNest: PropTypes.bool,
};

export default DropDown;
